#include "NoArvore.h"

/*-----------------------------------------------------
  Construtor...
-----------------------------------------------------*/
NoArvore::NoArvore()
{
    this->mFilhos   = NULL;
    this->mConteudo = NULL;
}

/*-----------------------------------------------------
  Destrutor...
-----------------------------------------------------*/
NoArvore::~NoArvore()
{
    if (this->mFilhos != NULL) delete this->mFilhos;
}

/*-----------------------------------------------------
  Insere um filho no atual e retorna o noFilho
-----------------------------------------------------*/
NoArvore* NoArvore::inserirFilho(const char *filho)
{
    NoArvore *no = new NoArvore();

    no->setNo(this->getNivel() + 1, filho);
    no->setNoPai(this);

    if (this->mFilhos == NULL)
        this->mFilhos = new std::list<NoArvore *>;

    this->mFilhos->push_back(no);

    return no;
}

/*-----------------------------------------------------
  Insere um filho no atual e retorna o noFilho
-----------------------------------------------------*/
NoArvore* NoArvore::inserirFilho(std::list<std::string> *filho)
{
    NoArvore *no = new NoArvore();

    no->setNo(this->getNivel() + 1, filho);
    no->setNoPai(this);

    if (this->mFilhos == NULL)
        this->mFilhos = new std::list<NoArvore *>;

    this->mFilhos->push_back(no);

    return no;
}

/*-----------------------------------------------------
  Insere um nofilho (pode ser uma subArvore) no atual
  e retorna o noFilho e recalcula os niveis dos nos da
  subarvore
-----------------------------------------------------*/
NoArvore* NoArvore::inserirSubArvore(NoArvore *noFilho)
{
    noFilho->setNivel(this->getNivel() + 1);

    if (this->mFilhos == NULL)
        this->mFilhos = new std::list<NoArvore *>;

    this->recalcularNivel(noFilho);

    this->mFilhos->push_back(noFilho);

    return noFilho;
}

/*-----------------------------------------------------
  Percorre os nos filho do noAtual de forma recursiva
-----------------------------------------------------*/
void NoArvore::percorreNo(int &nivelBase, NoArvore *noAtual)
{
    std::list<NoArvore*>::reverse_iterator it;

    if (noAtual->temFilho())
    {
        nivelBase++;

        for (it = noAtual->mFilhos->rbegin(); it != noAtual->mFilhos->rend(); it++)
        {
            this->percorreNo(nivelBase, (*it));
        }

        nivelBase--;

        noAtual->setNivel(nivelBase);
    }
    else
    {
        noAtual->setNivel(nivelBase);
    }    
}

/*-----------------------------------------------------
  Recalcula o nivel dos nohs filhos do noBase
-----------------------------------------------------*/
void NoArvore::recalcularNivel(NoArvore *noBase)
{
    int nivelBase = noBase->getNivel();
    this->percorreNo(nivelBase, noBase);
}

/*-----------------------------------------------------
  Seta o nivel e o conteudo do no
-----------------------------------------------------*/
void NoArvore::setNo(int nivel, const char *elemento)
{
    if (this->mConteudo != NULL) delete this->mConteudo;

    if (elemento != NULL)
    {
        this->mConteudo = new char [strlen(elemento) + 1];
        strcpy(this->mConteudo, elemento);
    }
    else
    {
        this->mConteudo  = NULL;
        this->mExpressao = NULL;
    }
    this->mNivel    = nivel;
}


/*-----------------------------------------------------
  Seta o nivel e o conteudo do no
-----------------------------------------------------*/
void NoArvore::setNo(int nivel, std::list<std::string> *elemento)
{
   // if (this->mExpressao != NULL) delete this->mExpressao;

    if (elemento != NULL)
    {
        this->mExpressao = elemento;
    }
    else
    {
        this->mConteudo  = NULL;
        this->mExpressao = NULL;
    }
    this->mNivel    = nivel;
}

/*-----------------------------------------------------
  Retorna o conteudo do no
-----------------------------------------------------*/
char* NoArvore::getConteudo()
{
    return this->mConteudo;
}

/*-----------------------------------------------------
  Retorna a expressao do no
-----------------------------------------------------*/
std::list<std::string>* NoArvore::getExpressao()
{
    return this->mExpressao;
}

/*-----------------------------------------------------
  Seta o no pai do no atual
-----------------------------------------------------*/
void NoArvore::setNoPai(NoArvore *noPai)
{
    this->mNoPai = noPai;
}

/*-----------------------------------------------------
  Retorna o no pai do no atual
-----------------------------------------------------*/
NoArvore* NoArvore::getNoPai() const
{
    return (this->mNoPai);
}

/*-----------------------------------------------------
  Informa se o no atual tem filhos
-----------------------------------------------------*/
bool NoArvore::temFilho() const
{
    return (this->mFilhos == NULL ? false : true);
}

/*-----------------------------------------------------
  Atribui um nivel ao no atual
-----------------------------------------------------*/
void NoArvore::setNivel(int nivel)
{
    this->mNivel = nivel;
}

/*-----------------------------------------------------
  Retorna o nivel do no atual
-----------------------------------------------------*/
int NoArvore::getNivel() const
{
    return this->mNivel;
}

/*-----------------------------------------------------
  Retorna os filhos do no atual
-----------------------------------------------------*/
std::list<NoArvore*>* NoArvore::getFilhos() const
{
    return this->mFilhos;
}
